package com.fulizhe.catlocal.integration.springboot.config;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;

import com.dianping.cat.Cat;
import com.dianping.cat.message.Transaction;

import cn.hutool.core.util.ArrayUtil;

@Aspect
@Component
public class CatAopAspect {

	@Around(value = "@annotation(CatAnnotation) || @annotation(CatControllerAnnotation) || @annotation(CatServiceAnnotation)")
	public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
		Method method = joinPointObject.getMethod();
		CatAnnotation mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(method, CatAnnotation.class);

		Transaction t = Cat.newTransaction("method", method.getName());
		Cat.logEvent("LAYER", ArrayUtil.join(new String[] { mergedAnnotation.layer(),
				method.getDeclaringClass().getSimpleName() + "." + method.getName() }, ";"));
		try {
			Object res = pjp.proceed();
			t.setSuccessStatus();
			return res;
		} catch (Throwable e) {
			t.setStatus(e);
			Cat.logError(e);
			throw e;
		} finally {
			t.complete();
		}

	}

	/**
	 * 判断是否有注解 Annotation
	 *
	 * @param method
	 *            Method
	 * @param annotationType
	 *            注解类
	 * @param <A>
	 *            泛型标记
	 * @return {boolean}
	 */
	static <A extends Annotation> boolean isAnnotated(Method method, Class<A> annotationType) {
		// 先找方法，再找方法上的类
		boolean isMethodAnnotated = AnnotatedElementUtils.isAnnotated(method, annotationType);
		if (isMethodAnnotated) {
			return true;
		}
		// 获取类上面的Annotation，可能包含组合注解，故采用spring的工具类
		Class<?> targetClass = method.getDeclaringClass();
		return AnnotatedElementUtils.isAnnotated(targetClass, annotationType);
	}

}